#include "table.h"

table table_init(size_t capacity)
{
	int i;
	table t = (table)malloc(sizeof(struct ctbl));
	if( t == NULL) { printf("table_init(): out of memory.\n"); exit(-1); }
	t->entries = (entry*)malloc(sizeof(entry)*capacity);
	if( t->entries == NULL ) {printf("table_init(): out of memory.\n"); exit(-1); }
	for(i=0;i<capacity;i++) t->entries[i].type = EMPTY;
	t->ctblcap = capacity;
	t->ctblsize = 0;

	return t;
}


unsigned long hash(char *s, int sz) {
	int hash = 5381;
	int i;
	for(i=0; i<sz;i++,s++) hash = ((hash << 5) + hash) + toupper(*s);
	return hash;
}

/* This performs the lookup */
/* Modified this to return a structure containing both the type of the symbol table item and its index */

lookup_result* table_includes(table t, char* key)
{
	lookup_result *to_return = (lookup_result*) malloc (sizeof (lookup_result));

	int keysz = strlen(key);
	int index = table_find(t,key);

	/*if the bin is empty or what's in the bin doesn't match - I'm not sure why this is case insensitive */
	if(t->entries[index].type == EMPTY || (! strncasecmp(t->entries[index].name,key,keysz)==0)) {
		to_return->index = -1;	
		return to_return;
	}

	to_return->type = t->entries[index].type;
	to_return->index = index;
	return to_return;
}


/* This finds where to put a new value */
/* modified full to ! empty */

int table_find(table t, char* key)
{
	int keysz = strlen(key);
	int currentindex = hash(key,keysz) % (t->ctblcap);
	int ncollisions = 0;

	/*is this right?*/

	while( t->entries[currentindex].type != EMPTY &&
		 	(strncasecmp(t->entries[currentindex].name,key,keysz)!=0)) {
		currentindex += 2 * ++ncollisions - 1;
		if( currentindex >= t->ctblcap) currentindex -= t->ctblcap;
	}

	return currentindex;
}

/* this inserts the new value */
/* modified to take a type */

int table_insert(table t, char* key, int typename, void* value, size_t size)
{
	int keysz = strlen(key);
	int index = table_find(t,key);

	/*if it possible this isn't met - and if so this just aborts...*/
	if(t->entries[index].type == EMPTY) {
		t->entries[index].type = typename;
		t->entries[index].name = memcpy(calloc(sizeof(char),keysz+1),key,keysz);
		t->entries[index].data = (size == 0) ? (int*)value : memcpy(malloc(size),value,size);
		t->entries[index].size = size;
		t->ctblsize++;
	}
	if(t->ctblsize == t->ctblcap>>1) {
		int i;
		int oldcap = t->ctblcap;
		entry* oldentries = t->entries;
		t->entries = (entry*)malloc(sizeof(entry)*oldcap*2);
		t->ctblsize = 0;
		t->ctblcap = oldcap<<1;
		for(i=0;i<t->ctblcap;i++) t->entries[i].type = EMPTY;
		for(i=0;i<oldcap;i++) {
			if(oldentries[i].type != EMPTY) {
				table_insert(t,oldentries[i].name,oldentries[i].type, oldentries[i].data,oldentries[i].size);
				free(oldentries[i].name);
			}
		}
		free(oldentries);
	}
	return index;
}

/*Re-written to take the table index as the input - it will only be called after table_includes - so the caller has the index
 already - also now returns the address and the size*/
rh_address* table_retrieve(table t, int offset)
{
	rh_address* temp = (rh_address*) malloc (sizeof (rh_address));
	temp->addr = t->entries[offset].data;
	temp->size = t->entries[offset].size;

	return temp;
}

void  table_print(table t)
{
	int i;
	for(i=0;i<t->ctblcap;i++)
		if(t->entries[i].type != EMPTY) 
			printf("[%d] %s => %x\n",i,t->entries[i].name,(int)t->entries[i].data);
	return;
}

int table_assign(table t, char* key, void* value, size_t size)
 {
	 int keysz = strlen(key);
	 int index = table_find(t,key);
	 if(t->entries[index].size != 0) free(t->entries[index].data);
	 t->entries[index].data = (size == 0) ? (int*)value : memcpy(malloc(size),value,size); 
	 t->entries[index].size = size;
	 return index;
 }








 
